package com.xian;

import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

/**
 * ATM系统入口类
 * <p>
 * 系统准备内容分析:
 * ①每个用户的账户信息都是一个对象，需要提供账户类。
 * ②需要准备一个容器，用于存储系统全部账户对象信息。
 * ③首页只需要包含:登录和注册2个功能。
 * <p>
 * 实现步骤:
 * 定义账户类，用于后期创建账户对象封装用户的账户信息。
 * 账户类中的信息至少需要包含（卡号、姓名、密码、余额、取现额度)
 * 需要准备一个ArrayList的集合，用于存储系统用户的账户对象。
 * 需要展示欢迎页包含2个功能:开户功能、登录账户。
 */
public class ATMSystem {
    public static void main(String[] args) {

        //1.定义账户类，用于后期创建账户对象封装用户的账户信息。

        //2.定义一个集合容器，负责以后存储全部的账户对象,进行相关的业务操作。
        ArrayList<Account> accounts = new ArrayList<>();

        Scanner sc = new Scanner(System.in);
        //3.展示系统的首页
        while (true) {
            System.out.println("====================小贤ATM系统=======================");
            System.out.println("1、账户登录");
            System.out.println("2、账户开户");


            System.out.println("请选择操作:");
            int command = sc.nextInt();
            switch (command) {
                case 1:
                    login(accounts, sc);
                    break;
                case 2:
                    register(accounts, sc);
                    break;
                default:
                    System.out.println("您输入的操作命令不存在~~~");
            }
        }
    }


    /**
     * @param accounts 开户功能实现步骤
     *                 →
     *                 ①开户应该定义成一个方法，并传入账户集合:
     *                 public static void register(ArrayList<Account> accounts)f{...}
     *                 ②创建一个Account账户类的对象用于封装账户信息（姓名、密码、卡号)
     *                 ③键盘录入姓名、密码、确认密码（需保证两次密码一致)
     *                 ④生成账户卡号，卡号必须由系统自动生成8位数字（必须保证卡号的唯一)
     *                 ⑤把Account账户对象存入到集合accounts中去。
     */


    /**
     * 开户功能
     *
     * @param accounts
     * @param sc
     */
    private static void register(ArrayList<Account> accounts, Scanner sc) {
        System.out.println("=====================系统开户操作=====================");
        //1.创建一个账户对象，用于后期封装账户信息
        Account account = new Account();

        System.out.println("请输入账户用户名:");
        String userName = sc.next();
        account.setUserName(userName);

        //2.录入账户信息，注入账户对象
        while (true) {
            System.out.println("请输入账户密码:");
            String passWord = sc.next();
            System.out.println("请再次输入账户密码:");
            String okPassWord = sc.next();
            if (okPassWord.equals(passWord)) {
                account.setPassWord(okPassWord);
                break;
            } else {
                System.out.println("两次输入不一致！！！");
            }
        }

        System.out.println("请输入当次限额:");
        double quotaMoney = sc.nextDouble();
        account.setQuotaMoney(quotaMoney);

        //为账户随机一个8位且不重复的号码（独立方法）
        String cardId = getRandomCardId(accounts);
        account.setCardId(cardId);

        //3.把账户对象添加到账户集合
        accounts.add(account);
        System.out.println("恭喜，" + userName + "先生/女士,您开户成功，卡号是:" + cardId);
    }

    /**
     * 为账户生成8位与其他账户卡号不同的号码
     *
     * @return
     */
    private static String getRandomCardId(ArrayList<Account> accounts) {
        Random random = new Random();
        //1.先生成8位
        while (true) {
            String cardId = "";
            for (int i = 0; i < 8; i++) {
                cardId += random.nextInt(10);
            }

            //2、判断这个8位的卡号是否与其他账户的卡号重复了。
            Account acc = getAccountByCardId(cardId, accounts);
            if (acc == null) {
                return cardId;
            }
        }
    }

    /**
     * 根据卡号查询出一个账户对象出来
     *
     * @param cardId
     * @param accounts
     * @return
     */
    private static Account getAccountByCardId(String cardId, ArrayList<Account> accounts) {
        for (int i = 0; i < accounts.size(); i++) {
            Account acc = accounts.get(i);
            if (acc.getCardId().equals(cardId)) {
                return acc;
            }
        }
        return null;
    }

    /**
     * 分析
     * ①登录功能应该定义成一个方法，并传入账户集合:
     * public static void login(ArrayList<Account> accounts){...}
     * ②让用户输入卡号，根据卡号去账户集合中查询账户对象。
     * ③如果没有找到账户对象，说明登录卡号不存在，提示继续输入卡号。
     * ④如果找到了账户对象，说明卡号存在，继续输入密码。
     * ⑤如果密码不正确，提示继续输入密码
     * ⑥如果密码也正确，登陆成功!!
     */

    /**
     * 登录功能
     *
     * @param accounts
     * @param sc
     */
    private static void login(ArrayList<Account> accounts, Scanner sc) {
        System.out.println("=====================系统登录操作========================");

        //1.判断账户集合中是否存在账户
        if (accounts.size() == 0) {
            System.out.println("对不起，当前系统中，无任何账户，请先开户，再来登录~~~");
            return;  //卫语言风格，解决方法的执行
        }

        //2.正式进入登录操作
        while (true) {
            System.out.println("请您输入登录卡号:");
            String cardId = sc.next();

            //3.判断卡号是否存在:根据卡号去账户集合中查询账户对象。
            Account acc = getAccountByCardId(cardId, accounts);
            if (acc != null) {
                while (true) {
                    //卡号存在
                    //1.让用户输入密码，认证密码
                    System.out.println("请输入密码:");
                    String pwd = sc.next();
                    if (acc.getPassWord().equals(pwd)) {
                        //登录成功
                        System.out.println("恭喜您," + acc.getUserName() + "先生/女士，进入系统，您的卡号是:" + acc.getCardId());

                        //显示登录后操作页
                        showUserCommand(sc, acc, accounts);
                        return;//干掉登录方法


                    } else {
                        System.out.println("对不起，您输入的密码有误！！！");
                    }
                }
            } else {
                System.out.println("对不起，系统中不存在该卡号！！！");
            }
        }
    }

    /**
     * 展示登录后的操作页
     * <p>
     * 登录后用户操作页设计、查询账户、退出账户功能分析
     * ①用户登录成功后，需要进入用户操作页。
     * ②查询就是直接展示当前登录成功的账户对象的信息。
     * ③退出账户是需要回到首页的。
     */
    private static void showUserCommand(Scanner sc, Account acc, ArrayList<Account> accounts) {
        while (true) {
            System.out.println("===================用户操作页=====================");
            System.out.println("1、查询账户");
            System.out.println("2、存款");
            System.out.println("3、取款");
            System.out.println("4、转账");
            System.out.println("5、修改密码");
            System.out.println("6、退出");
            System.out.println("7、注销账户");

            int command = sc.nextInt();
            switch (command) {
                case 1:
                    //查询账户
                    showAccount(acc);
                    break;
                case 2:
                    //存款
                    depositMoney(acc, sc);
                    break;
                case 3:
                    //取款
                    drawMoney(acc, sc);
                    break;
                case 4:
                    //转账
                    transferMoney(sc, acc, accounts);
                    break;
                case 5:
                    //修改密码
                    updatePassword(sc, acc);
                    return; //让当前方法停止执行
                case 6:
                    //退出
                    System.out.println("退出成功，欢迎下次光临!!!");
                    return; //让当前方法停止执行
                case 7:
                    //注销账户
                    if (deleteAccount(sc, acc, accounts)) {
                        return; //让当前方法停止执行,返回首页
                    } else {
                        //还是在操作页玩
                        break;
                    }


                default:
                    System.out.println("您输入的操作命令不正确~~");

            }
        }

    }


    /**
     * 展示账户信息
     *
     * @param acc
     */
    private static void showAccount(Account acc) {
        System.out.println("==================当前账户信息如下==================");
        System.out.println("卡号:" + acc.getCardId());
        System.out.println("户主:" + acc.getUserName());
        System.out.println("余额:" + acc.getMoney());
        System.out.println("限额:" + acc.getQuotaMoney());
    }

    /**
     * 存钱
     *
     * @param acc
     * @param sc  存款分析
     *            ①存款就是拿到当前账户对象。
     *            ②然后让用户输入存款的金额。
     *            ③调用账户对象的setMoney方法将账户余额修改成存钱后的余额。
     *            ④存钱后需要查询‘下账户信息，确认是否存钱成功了!
     */
    private static void depositMoney(Account acc, Scanner sc) {
        System.out.println("==================用户存钱操作==================");
        System.out.println("请输入存款金额:");
        double money = sc.nextDouble();

        //更新账户余额：原来的钱+新存入的钱
        acc.setMoney(acc.getMoney() + money);
        System.out.println("恭喜您，存钱成功，当前账户信息如下:");
        showAccount(acc);
    }

    /**
     * 取款
     *
     * @param acc
     * @param sc  取款分析
     *            1取款需要先判断账户是否有钱。
     *            ②有钱则拿到自己账户对象。
     *            ③然后让用户输入取款金额
     *            ④判断取款金额是否超过了当次限额，以及余额是否足够
     *            ⑤满足要求则调用账户对象的setMoney方法完成金额的修改。
     */
    private static void drawMoney(Account acc, Scanner sc) {
        System.out.println("==================用户取钱操作==================");
        //1.判断是否足够100元，，，100才能取
        if (acc.getMoney() < 100) {
            System.out.println("对不起，当前余额不足100元，不能取款！！！");
            return;
        }

        while (true) {
            //2.提示用户输入取款金额
            System.out.println("请输入取款金额:");
            double money = sc.nextDouble();

            //3.判断这个金额是否满足要求
            if (money > acc.getQuotaMoney()) {
                System.out.println("对不起，当前取款金额大于每次限额，每次最多取:" + acc.getQuotaMoney());
            } else {
                //没有超过限额
                //4.判断是否超过余额
                if (money > acc.getMoney()) {
                    System.out.println("余额不足，您当前账户余额为:" + acc.getMoney());
                } else {
                    //可以取钱了
                    System.out.println("恭喜您，取钱" + money + "元，成功！！！");
                    //更新余额
                    acc.setMoney(acc.getMoney() - money);
                    //取钱结束
                    showAccount(acc);
                    return;  //干掉取钱方法
                }
            }
        }

    }

    /**
     * @param sc       扫描器
     * @param acc      自己账户对象
     * @param accounts 全部账户集合
     *                 <p>
     *                 ①转账功能需要判断系统中是否有2个账户对象及以上。
     *                 ②同时还要判断自己账户是否有钱。
     *                 ③接下来需要输入对方卡号，判断对方账户是否存在。
     *                 ④对方账户存在还需要认证对方户主的姓氏。
     *                 ⑤满足要求则可以把自己账户对象的金额修改到对方账户对象中去。
     */
    private static void transferMoney(Scanner sc, Account acc, ArrayList<Account> accounts) {
        System.out.println("==================用户转账操作==================");

        //1.判断系统中是否有2个账户对象及以上
        if (accounts.size() < 2) {
            System.out.println("当前系统中不足两个账户，不能进行转账，先去开户吧~~~");
            return;  //结束当前方法
        }

        //2.开始转账,,判断自己账户是否有钱
        if (acc.getMoney() == 0) {
            System.out.println("对不起，您自己都没钱，就别转了吧！！！！");
            return;//结束当前方法
        }

        //3.真正开始转账
        while (true) {
            System.out.println("请您输入对方账户卡号:");
            String cardId = sc.next();

            //这个卡号不能是自己的
            if (cardId.equals(acc.getCardId())) {
                System.out.println("对不起，您不可以给自己转账!!!");
                continue;
            }


            //判断这个卡号是否存在：根据卡号取查对方账户对象
            Account account = getAccountByCardId(cardId, accounts);
            if (account == null) {
                System.out.println("对不起，您输入对方的这个账号不存在！！！");
            } else {
                //这个账户对象存在
                String userName = account.getUserName();
                String tip = "*" + userName.substring(1);

                System.out.println("请您输入[" + tip + "]的姓氏");

                String preName = sc.next();

                //认证姓氏是否正确
                if (userName.startsWith(preName)) {
                    while (true) {
                        //认证通过，真正开始转账了
                        System.out.println("请您输入转账金额：");
                        double money = sc.nextDouble();

                        //判断余额是否足够
                        if (money > acc.getMoney()) {
                            System.out.println("对不起，您余额不足，最多可以转账：" + acc.getMoney() + "元");
                        } else {
                            //余额足够
                            acc.setMoney(acc.getMoney() - money);
                            account.setMoney(account.getMoney() + money);
                            System.out.println("转账成功！！！,您的余额还剩：" + acc.getMoney());
                            return;//干掉转账方法
                        }
                    }


                } else {
                    System.out.println("对不起，您输入的信息有误！！！");
                }


            }

        }
    }

    /**
     * 修改密码
     *
     * @param sc
     * @param acc 分析
     *            ①修改密码就是把当前对象的密码属性使用set方法进行更新。
     *            ②销户是从集合对象中删除当前对象，并回到首页。
     */
    private static void updatePassword(Scanner sc, Account acc) {
        System.out.println("==================用户修改密码==================");
        while (true) {
            System.out.println("请输入当前密码；");
            String oldPwd = sc.next();

            //1.判断密码是否正确
            if (acc.getPassWord().equals(oldPwd)) {
                while (true) {
                    //密码正确
                    //2.输入新密码
                    System.out.println("请输入新密码：");
                    String newPwd = sc.next();
                    System.out.println("请再次输入新密码：");
                    String newPwd1 = sc.next();

                    if (newPwd.equals(newPwd1)) {
                        //两次密码一致
                        acc.setPassWord(newPwd);
                        System.out.println("恭喜您，密码修改成功！！！");
                        return;
                    } else {
                        System.out.println("两次输入的密码不一致！！！");
                    }
                }

            } else {
                System.out.println("请重新输入:");
            }
        }

    }


    /**
     * 销户功能
     *
     * @param sc
     * @param acc
     * @param accounts
     */
    private static boolean deleteAccount(Scanner sc, Account acc, ArrayList<Account> accounts) {
        System.out.println("==================用户销户==================");
        //从当前账户集合中，删除当前账户对象，销毁就完成了
        System.out.println("确定销户吗？y/n");
        String res = sc.next();
        switch (res) {
            case "y":
                //真正的销户
                if (acc.getMoney() > 0) {
                    System.out.println("您的账户还有:" + acc.getMoney() + "元，不允许销户！！！");
                } else {
                    accounts.remove(acc);
                    System.out.println("您的账户销户完成！！！");
                    return true; //销户完成，返回首页
                }
                break;
            default:
                System.out.println("好的，当前账户继续保留~~~");
        }
        return false;
    }


}
